package com.jzo2o.health.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jzo2o.api.trade.NativePayApi;
import com.jzo2o.api.trade.TradingApi;
import com.jzo2o.api.trade.dto.request.NativePayReqDTO;
import com.jzo2o.api.trade.dto.response.ExecutionResultResDTO;
import com.jzo2o.api.trade.dto.response.NativePayResDTO;
import com.jzo2o.api.trade.dto.response.TradingResDTO;
import com.jzo2o.api.trade.enums.PayChannelEnum;
import com.jzo2o.common.constants.MqConstants;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.constant.TradeConstants;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.handler.OrdersHandler;
import com.jzo2o.health.model.UserThreadLocal;
import com.jzo2o.health.model.domain.*;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.model.dto.request.OrdersCancelReqDTO;
import com.jzo2o.health.model.dto.request.OrdersPageQueryReqDTO;
import com.jzo2o.health.model.dto.request.PlaceOrderReqDTO;
import com.jzo2o.health.model.dto.response.*;
import com.jzo2o.health.properties.TradeProperties;
import com.jzo2o.health.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.rabbitmq.client.RabbitClient;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yaml.snakeyaml.events.Event;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author dmx
 * @since 2024-12-14
 */
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersService {

    private static final String SORT_BY = "sort_by";

    @Autowired
    private ISetmealService setmealService;

    @Autowired
    private IMemberService memberService;


    @Autowired
    private ReservationSettingService reservationSettingService;
    /**
     * 用户预约下单
     *
     * @param placeOrderReqDTO
     * @return
     */
    @Override
    public PlaceOrderResDTO place(PlaceOrderReqDTO placeOrderReqDTO) {
        //1.判断placeOrderReqDTO是否为空
        if (ObjectUtils.isEmpty(placeOrderReqDTO)) {
            throw new BadRequestException("非法数据");
        }
        //2.根据套餐id获取套餐详情，并封装到order中
        Setmeal setmeal = setmealService.findById(placeOrderReqDTO.getSetmealId());
        if (ObjectUtils.isEmpty(setmeal)) {
            throw new BadRequestException("套餐不存在");
        }
        Orders orders = new Orders();
        orders.setSetmealId(placeOrderReqDTO.getSetmealId());//套餐id
        orders.setSetmealName(setmeal.getName());
        orders.setSetmealSex(setmeal.getSex());
        orders.setSetmealAge(setmeal.getAge());
        orders.setSetmealImg(setmeal.getImg());
        orders.setSetmealRemark(setmeal.getRemark());
        orders.setSetmealPrice(BigDecimal.valueOf(setmeal.getPrice()));
        orders.setReservationDate(placeOrderReqDTO.getReservationDate());
        //3.设置order_status（0） pay_status（0）
        orders.setOrderStatus(OrderStatusEnum.NO_PAY.getStatus());
        orders.setPayStatus(OrderPayStatusEnum.NO_PAY.getStatus());

        //4.设置体检人信息
        orders.setCheckupPersonName(placeOrderReqDTO.getCheckupPersonName());
        orders.setCheckupPersonSex(placeOrderReqDTO.getCheckupPersonSex());
        orders.setCheckupPersonPhone(placeOrderReqDTO.getCheckupPersonPhone());
        orders.setCheckupPersonIdcard(placeOrderReqDTO.getCheckupPersonIdcard());
        //5.设置用户信息
        orders.setMemberId(UserThreadLocal.currentUserId());
        Member member = memberService.getById(UserThreadLocal.currentUserId());
        if (ObjectUtils.isEmpty(member)) {
            throw new BadRequestException("用户不存在");
        }
        orders.setMemberPhone(member.getPhone());
        //6.插入数据库
        boolean saveResult = this.save(orders);
        if (!saveResult) {
            throw new DBException("新增订单失败");
        }
        //预约设置表中对用的order_date的number-1   reservations+1
        ReservationSetting reservationSetting = reservationSettingService.lambdaQuery()
                .eq(ReservationSetting::getOrderDate, orders.getReservationDate())
                .one();
        if (BeanUtils.isEmpty(reservationSetting)){
            throw new DBException("预约日期不存在");
        }
        boolean update = reservationSettingService.lambdaUpdate()
                .set(ReservationSetting::getNumber, reservationSetting.getNumber() - 1)
                .set(ReservationSetting::getReservations, reservationSetting.getReservations() + 1)
                .eq(ReservationSetting::getId,reservationSetting.getId())
                .update();
        if (!update){
            throw new DBException("修改失败");
        }
        return new PlaceOrderResDTO(orders.getId());
    }


    @Autowired
    private NativePayApi nativePayApi;

    @Autowired
    private TradeProperties tradeProperties;

    @Autowired
    private OrdersServiceImpl owner;

    /**
     * 用户端生成支付二维码
     *
     * @param id
     * @param tradingChannel
     * @return
     */
    @Override
    public OrdersPayResDTO pay(Long id, PayChannelEnum tradingChannel) {
        //1.判断订单是否存在
        Orders orders = this.getById(id);
        if (ObjectUtils.isEmpty(orders)) {
            throw new BadRequestException("订单不存在");
        }
        //2.调用三方接口
        NativePayReqDTO nativePayReqDTO = new NativePayReqDTO();

        Boolean channel = false;
        //判断是那种支付方式
        Long merchantId = ObjectUtils.equals(tradingChannel, PayChannelEnum.ALI_PAY) ? tradeProperties.getAliEnterpriseId() : tradeProperties.getWechatEnterpriseId();

        nativePayReqDTO.setEnterpriseId(merchantId);//  1
        nativePayReqDTO.setProductOrderNo(orders.getId());//设置系统订单号  1
        nativePayReqDTO.setTradingChannel(tradingChannel);//设置支付渠道1
        //nativePayReqDTO.setTradingAmount(orders.getSetmealPrice());//设置付款金额
        nativePayReqDTO.setTradingAmount(BigDecimal.valueOf(0.01));//测试用  1
        nativePayReqDTO.setMemo(orders.getSetmealName());//设置商品描述 1
        nativePayReqDTO.setProductAppId(TradeConstants.PRODUCT_APP_ID);//设置APPid
        //nativePayReqDTO.setProductAppId(null);
        if (ObjectUtils.isNotEmpty(orders.getTradingOrderNo()) && !orders.getTradingChannel().equals(tradingChannel)) {
            channel = true;
        }
        nativePayReqDTO.setChangeChannel(channel);//设置是否更改支渠道   1
        NativePayResDTO downLineTrading = nativePayApi.createDownLineTrading(nativePayReqDTO);
        //3.修改对应订单的
        if (ObjectUtils.isEmpty(downLineTrading)) {
            throw new BadRequestException("支付失败");
        }
//        boolean update = this.lambdaUpdate()
//                .set(Orders::getTradingChannel, tradingChannel)
//                .set(Orders::getTradingOrderNo, downLineTrading.getTradingOrderNo())
//                .eq(Orders::getId, id).update();
//        if (!update){
//            throw new DBException("修改失败");
//        }
        owner.updateOrders(id, tradingChannel, downLineTrading);
        OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(downLineTrading, OrdersPayResDTO.class);
        ordersPayResDTO.setPayStatus(orders.getPayStatus());

        return ordersPayResDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrders(Long id, PayChannelEnum tradingChannel, NativePayResDTO downLineTrading) {
        boolean update = this.lambdaUpdate()
                .set(Orders::getTradingChannel, tradingChannel.getValue())
                .set(Orders::getTradingOrderNo, downLineTrading.getTradingOrderNo())
                .eq(Orders::getId, id)
                .update();
        if (!update) {
            throw new DBException("修改失败");
        }
    }

    @Autowired
    private TradingApi tradingApi;

    /**
     * 查询订单支付结果
     *
     * @param id
     * @return
     */
    @Override
    public OrdersPayResDTO QueryPayResult(Long id) {

        //1.判断订单是否存在
        Orders orders = this.getById(id);
        if (ObjectUtils.isEmpty(orders)) {
            throw new BadRequestException("订单不存在");
        }
        //2.判断支付订单是否为空
        if (ObjectUtils.isNull(orders.getTradingOrderNo())) {
            throw new BadRequestException("异常订单");
        }
        //3.判断是否支付成功
        OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(orders, OrdersPayResDTO.class);
        if (ObjectUtils.equals(orders.getPayStatus(), OrderPayStatusEnum.PAY_SUCCESS.getStatus())) {
            return ordersPayResDTO;
        }
        //4.调用微信支付的确认接口查看是否交易成功
        TradingResDTO tradResultByTradingOrderNo = tradingApi.findTradResultByTradingOrderNo(ordersPayResDTO.getTradingOrderNo());
        if (ObjectUtils.isEmpty(tradResultByTradingOrderNo)){
            throw new BadRequestException("支付订单不存在");
        }

        //5.如果支付成功更新数据库中支付相关的状态
//        boolean update = lambdaUpdate()
//                .set(Orders::getOrderStatus, OrderStatusEnum.WAITING_CHECKUP.getStatus())
//                .set(Orders::getPayStatus, OrderPayStatusEnum.PAY_SUCCESS.getStatus())
//                .set(Orders::getPayTime, LocalDate.now())
//                .set(Orders::getTransactionId, tradResultByTradingOrderNo.getTransactionId())
//                .eq(Orders::getId, id).update();
//        if (!update){
//            throw new DBException("更新失败");
//        }
        owner.updatePayStatus(id,tradResultByTradingOrderNo);
        //6.封装数据返回
        OrdersPayResDTO ordersPayResDTO1 = BeanUtils.copyBean(tradResultByTradingOrderNo, OrdersPayResDTO.class);
        return ordersPayResDTO1;
    }



    @Transactional(rollbackFor = Exception.class)
    public void updatePayStatus(Long id,TradingResDTO tradResultByTradingOrderNo){
        boolean update = lambdaUpdate()
                .set(Orders::getOrderStatus, OrderStatusEnum.WAITING_CHECKUP.getStatus())
                .set(Orders::getPayStatus, OrderPayStatusEnum.PAY_SUCCESS.getStatus())
                .set(Orders::getPayTime, LocalDate.now())
                .set(Orders::getTransactionId, tradResultByTradingOrderNo.getTransactionId())
                .eq(Orders::getId, id).update();
        if (!update){
            throw new DBException("更新失败");
        }
    }

    /**
     * 分页查询
     * @param ordersStatus
     * @param sortBy
     * @return
     */
    @Override
    public List<OrdersResDTO> pageQuery(Integer ordersStatus, Long sortBy) {
        //1.构建查询条件
        LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery()
                .eq(ObjectUtils.isNotNull(ordersStatus), Orders::getOrderStatus, ordersStatus)
                .lt(ObjectUtils.isNotNull(sortBy), Orders::getSortBy, sortBy)
                .eq(Orders::getMemberId, UserThreadLocal.currentUserId());
        Page<Orders> queryPage = new Page<>();
        queryPage.addOrder(OrderItem.desc(SORT_BY));
        queryPage.setSearchCount(false);
        //2.查询订单列表
        Page<Orders> ordersPage = baseMapper.selectPage(queryPage, queryWrapper);
        List<Orders> records = ordersPage.getRecords();
        List<OrdersResDTO> ordersResDTOS = BeanUtils.copyToList(records, OrdersResDTO.class);
        return ordersResDTOS;
    }

    @Autowired
    private IOrdersCancelledService ordersCancelledService;



    /**
     * 用户取消订单
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(OrdersCancelReqDTO dto,Boolean isSystem) {

        if (ObjectUtils.isEmpty(dto)){
            throw new BadRequestException("请求异常");
        }

        Orders orders = this.getById(dto.getId());
        if (ObjectUtils.isEmpty(orders)){
            throw new BadRequestException("订单不存在");
        }
        //1.修改订单的状态
        boolean updateStatus = lambdaUpdate()
                .set(Orders::getOrderStatus, OrderStatusEnum.CANCELLED.getStatus())
                .eq(Orders::getId, dto.getId())
                .update();
        if (!updateStatus){
            throw new DBException("修改状态失败");
        }
        //2.增加取消订单
        OrdersCancelled ordersCancelled = new OrdersCancelled();
        ordersCancelled.setId(dto.getId());
        ordersCancelled.setCancelReason(dto.getCancelReason());//设置取消原因
        if (!isSystem){
            ordersCancelled.setCancellerId(UserThreadLocal.currentUser().getId());//设置取消人id
            ordersCancelled.setCancellerName(UserThreadLocal.currentUser().getName());//设置取消人姓名
        }

        ordersCancelled.setCancelTime(LocalDateTime.now());//设置取消时间
        boolean save = ordersCancelledService.save(ordersCancelled);
        if (!save){
            throw new DBException("新增失败");
        }
        //3.预约设置可预约人数+1，已预约人数-1
        ReservationSetting reservationSetting1 = reservationSettingService.lambdaQuery()
                .eq(ReservationSetting::getOrderDate, orders.getReservationDate())
                .one();
       // ReservationSetting reservationSetting = new ReservationSetting();

        LambdaUpdateWrapper<ReservationSetting> updateWrapper = Wrappers.<ReservationSetting>lambdaUpdate()
                .set(ReservationSetting::getNumber, reservationSetting1.getNumber() + 1)
                .set(ReservationSetting::getReservations, reservationSetting1.getReservations() - 1)
                .eq(ReservationSetting::getOrderDate, orders.getReservationDate());
        boolean updateReservationSetting = reservationSettingService.update(updateWrapper);
        if (!updateReservationSetting){
            throw new DBException("修改预约设置失败");
        }
    }


    @Autowired
    private IOrdersRefundService iOrdersRefundService;

    @Autowired
    private OrdersHandler ordersHandler;
    /**
     * 用户端订单退款
     * @param ordersCancelReqDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refund(OrdersCancelReqDTO ordersCancelReqDTO) {

        Orders orders = this.getById(ordersCancelReqDTO.getId());
        //1.判断订单是否存在，以及订单状态
        if (ObjectUtils.isEmpty(orders)){
            throw new BadRequestException("订单不存在");
        }
        if (!OrderPayStatusEnum.PAY_SUCCESS.getStatus().equals(orders.getPayStatus())){
            throw new BadRequestException("订单退款异常");
        }
        //2.先取消订单
        owner.cancel(ordersCancelReqDTO,false);
        //3.生成待退款订单
        OrdersRefund ordersRefund = new OrdersRefund();
        ordersRefund.setId(orders.getId());
        ordersRefund.setTradingOrderNo(orders.getTradingOrderNo());//设置支付服务交易单号
        ordersRefund.setRealPayAmount(orders.getSetmealPrice());//设置退款金额
        boolean save = iOrdersRefundService.save(ordersRefund);
        if (!save){
            throw new DBException("新增退款单失败");
        }
        //4.异步调用退款接口
        ordersHandler.ordersRefundHandle(ordersRefund);
    }

    /**
     * 用户端查询订单详情
     * @param id
     * @return
     */
    @Override
    public OrdersDetailResDTO detail(Long id) {
        Orders orders = this.getById(id);
        if (ObjectUtils.isEmpty(orders)){
            throw new BadRequestException("订单不存在");
        }
        return BeanUtils.copyBean(orders,OrdersDetailResDTO.class);
    }

    /**
     * 管理端分页查询
     * @param dto
     * @return
     */
    @Override
    public PageResult<OrdersResDTO> adminPageQuery(OrdersPageQueryReqDTO dto) {
        IPage<Orders> page=new Page<>(dto.getPageNo(),dto.getPageSize());
        IPage<Orders> page1 = this.lambdaQuery()
                .eq(ObjectUtils.isNotNull(dto.getOrderStatus()), Orders::getOrderStatus, dto.getOrderStatus())
                .likeRight(ObjectUtils.isNotNull(dto.getMemberPhone()), Orders::getMemberPhone, dto.getMemberPhone())
                .page(page);
        List<Orders> records = page1.getRecords();

        //类型转换
        List<OrdersResDTO> list = records.stream()
                .map(order -> {
                    OrdersResDTO ordersResDTO = BeanUtils.copyBean(order, OrdersResDTO.class);
                    // 其他字段的映射...
                    return ordersResDTO;
                })
                .collect(Collectors.toList());
        PageResult<OrdersResDTO> ordersResDTOPageResult = new PageResult<>();
        ordersResDTOPageResult.setList(list);
        ordersResDTOPageResult.setPages(page1.getPages());
        ordersResDTOPageResult.setTotal(page1.getTotal());
        return ordersResDTOPageResult;
    }
    /**
     * 根据订单状态统计订单数量
     * @return
     */
    @Override
    public OrdersCountResDTO countByStatus() {
        //分别查询对用的数量
        Integer count = lambdaQuery().count();//订单全部数量
        Integer noPayCount = lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.NO_PAY.getStatus()).count();//未支付订单数量
        Integer  waitingCheckupCount= lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.WAITING_CHECKUP.getStatus()).count();//待体检数量
        Integer completedCheckupCount = lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.COMPLETED_CHECKUP.getStatus()).count();//已体检数量
        Integer closedCount = lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.CLOSED.getStatus()).count();//已关闭订单数量
        Integer cancelledCount = lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.CANCELLED.getStatus()).count();//已取消订单数量
        //封装数据
        OrdersCountResDTO ordersCountResDTO = new OrdersCountResDTO();
        ordersCountResDTO.setNoPayCount(noPayCount);
        ordersCountResDTO.setTotalCount(count);
        ordersCountResDTO.setWaitingCheckupCount(waitingCheckupCount);
        ordersCountResDTO.setCompletedCheckupCount(completedCheckupCount);
        ordersCountResDTO.setClosedCount(closedCount);
        ordersCountResDTO.setCancelledCount(cancelledCount);

        return ordersCountResDTO;
    }


    /**
     * 管理端查询订单详情
     * @param id
     * @return
     */
    @Override
    public AdminOrdersDetailResDTO adminDetail(Long id) {
        Orders orders = this.getById(id);

       // AdminOrdersDetailResDTO adminOrdersDetailResDTO = BeanUtils.copyBean(orders, AdminOrdersDetailResDTO.class);
        AdminOrdersDetailResDTO adminOrdersDetailResDTO = new AdminOrdersDetailResDTO();
        AdminOrdersDetailResDTO.OrderInfo orderInfo = BeanUtils.copyBean(orders, AdminOrdersDetailResDTO.OrderInfo.class);
        AdminOrdersDetailResDTO.PayInfo payInfo = BeanUtils.copyBean(orders, AdminOrdersDetailResDTO.PayInfo.class);
        AdminOrdersDetailResDTO.RefundInfo refundInfo = BeanUtils.copyBean(orders, AdminOrdersDetailResDTO.RefundInfo.class);
        AdminOrdersDetailResDTO.CancelInfo cancelInfo = BeanUtils.copyBean(orders, AdminOrdersDetailResDTO.CancelInfo.class);
        adminOrdersDetailResDTO.setOrderInfo(orderInfo);
        adminOrdersDetailResDTO.setPayInfo(payInfo);
        adminOrdersDetailResDTO.setRefundInfo(refundInfo);
        adminOrdersDetailResDTO.setCancelInfo(cancelInfo);
        if (!OrderPayStatusEnum.NO_PAY.getStatus().equals(orders.getPayStatus())&&!OrderPayStatusEnum.PAY_SUCCESS.getStatus().equals(orders.getPayStatus())){
            OrdersCancelled ordersCancelled = ordersCancelledService.getById(orders.getId());
            refundInfo.setRefundStatus(orders.getPayStatus());
            refundInfo.setCancelReason(ordersCancelled.getCancelReason());
            refundInfo.setCancelTime(ordersCancelled.getCancelTime());

        }
        return adminOrdersDetailResDTO;
    }
}
